package com.imu.purse.config;

import com.imu.utils.EncryptUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.autoconfigure.amqp.RabbitProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;


@Configuration
@EnableCaching//启用缓存，这个注解很重要；
@EnableConfigurationProperties(RabbitProperties.class)
public class RabbitConfig {

    private static Logger logger = LoggerFactory.getLogger(RabbitConfig.class);
    private static final String queueName = RabbitUtil.getValue("queue.trans.name");

    private static final String exchangeName = RabbitUtil.getValue("queue.trans.exchange");

    private static  final String transKey = RabbitUtil.getValue("queue.trans.key");

    private static final String ytfTransQueueName = RabbitUtil.getValue("queue.ytf.trans.name");
    private static final String ytfTransExchageName = RabbitUtil.getValue("queue.ytf.trans.exchange");
    private  static final String ytfTransKey = RabbitUtil.getValue("queue.ytf.trans.key");

//    @Autowired
//    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RabbitProperties rabbitProperties;

    @Bean("rabbitConnectionFactory")
    public ConnectionFactory connectionFactory(){
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setAddresses(rabbitProperties.getAddresses());
        connectionFactory.setUsername(rabbitProperties.getUsername());
        String password = "";
        try{
            password = EncryptUtil.decrypt(rabbitProperties.getPassword());
        }catch(Exception e){

        }
        connectionFactory.setPassword(password);
        connectionFactory.setPublisherReturns(rabbitProperties.isPublisherReturns());
        connectionFactory.setPublisherConfirms(rabbitProperties.isPublisherConfirms());
        connectionFactory.setConnectionTimeout(rabbitProperties.getConnectionTimeout());
        logger.info(">>>>>>>>>>>>>>>rabbitConnectionFactory init success<<<<<<<<<<<<<");

        return connectionFactory;
    }
    /**
     * 定制化amqp模版      可根据需要定制多个
     * <p>
     * <p>
     * 此处为模版类定义 Jackson消息转换器
     * ConfirmCallback接口用于实现消息发送到RabbitMQ交换器后接收ack回调   即消息发送到exchange  ack
     * ReturnCallback接口用于实现消息发送到RabbitMQ 交换器，但无相应队列与交换器绑定时的回调  即消息发送不到任何一个队列中  ack
     *
     * @return the amqp template
     */
//    @Primary
    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public AmqpTemplate amqpTemplate(@Qualifier("rabbitConnectionFactory") ConnectionFactory connectionFactory) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate();
        Logger log = LoggerFactory.getLogger(RabbitTemplate.class);
        //使用jackson 消息转换器
        rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
        rabbitTemplate.setEncoding("UTF-8");
        // 开启returncallback
        //yml 需要 配置    publisher-returns: true
        rabbitTemplate.setMandatory(true);
        rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {
            String correlationId = message.getMessageProperties().getCorrelationIdString();
            log.debug("消息：{} 发送失败, 应答码：{} 原因：{} 交换机: {}  路由键: {}", correlationId, replyCode, replyText, exchange, routingKey);
        });
        //        消息确认  yml 需要配置   publisher-returns: true
        rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
            if (ack) {
                log.debug("消息发送到exchange成功,id: {}", correlationData.getId());
            } else {
                log.debug("消息发送到exchange失败,原因: {}", cause);
            }
        });
        rabbitTemplate.setConnectionFactory(connectionFactory);
        return rabbitTemplate;
    }

    /***
     * 以下定义转账的队列
     */
    @Bean("transDirectExchange")
    public Exchange transDirectExchange() {

        return ExchangeBuilder.directExchange(exchangeName).durable(true).build();
    }

    /**
     * 声明一个队列 支持持久化.
     *
     * @return the queue
     */
    @Bean("transDirectQueue")
    public Queue transDirectQueue() {

        return QueueBuilder.durable(queueName).build();
    }

    /**
     * 通过绑定键 将指定队列绑定到一个指定的交换机 .
     *
     * @param queue    the queue
     * @param exchange the exchange
     * @return the binding
     */
    @Bean
    public Binding transDirectBinding(@Qualifier("transDirectQueue") Queue queue, @Qualifier("transDirectExchange") Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with(transKey).noargs();
    }

    /***
     * 以下定义转账的队列
     */
    @Bean("ytfTransDirectExchange")
    public Exchange ytfTransDirectExchange() {
        return ExchangeBuilder.directExchange(ytfTransExchageName).durable(true).build();
    }

    /**
     * 声明一个队列 支持持久化.
     *
     * @return the queue
     */
    @Bean("ytfTransDirectQueue")
    public Queue ytfTransDirectQueue() {
        return QueueBuilder.durable(ytfTransQueueName).build();
    }

    /**
     * 通过绑定键 将指定队列绑定到一个指定的交换机 .
     *
     * @param queue    the queue
     * @param exchange the exchange
     * @return the binding
     */
    @Bean
    public Binding ytfTransDirectBinding(@Qualifier("ytfTransDirectQueue") Queue queue, @Qualifier("ytfTransDirectExchange") Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with(ytfTransKey).noargs();
    }

}
